/******************************************************************************
 * * alarm_api.c - API provided by alarm module
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/

#include "alarm_global.h"

/**
 * Initiate alarm module
 * param (in) VOID
 * return  VOID
 */
VOID Framework_Alarm_Init_Req(VOID)
{
    If_Framework_Reg_Info_t *RegInfo = NULL;
    NV_UI_Alarm_t           NvData;
    UINT8                   i;

    g_Alarm_Mng.Timer = NULL;

    /* read NVM */
    UI_NV_Read_Req(NV_SECTION_UI_ALARM, 0, sizeof(NV_UI_Alarm_t), (UINT8 *)&NvData);
    Hal_Mem_Copy(&g_Alarm_Mng.Alarm, &NvData, sizeof(NV_UI_Alarm_t));

    /* inform framework alarm on/off */
    for (i = 0; i < NV_ALARM_MAX_ALARM_NUM; i++)
    {
        if (TRUE == g_Alarm_Mng.Alarm.AlarmInfo[i].OnOff)
        {
            break;
        }
    }
    if (NV_ALARM_MAX_ALARM_NUM == i)
    {
        Framework_Alarm_Set_Alarm_Ind(FALSE);
    }
    else
    {
        Framework_Alarm_Set_Alarm_Ind(TRUE);
    }

    g_Alarm_Mng.RtcAlarmId = 0;

    /* register app */
    RegInfo             = (If_Framework_Reg_Info_t *)Hal_Mem_Alloc(sizeof(If_Framework_Reg_Info_t));
    RegInfo->NameTextId = PHONE_TEXT_ID_ALARM;
    RegInfo->AppImage   = IMG_MENU_ALARM;
    RegInfo->AppFunc    = Alarm_Main;
    Framework_App_Register_Req(RegInfo);
}

/**
 * Framework inform alarm ringing during power off
 * param (in) PowerOffAlarm: BOOL
 * return  VOID
 */
VOID Framework_Alarm_PowerOff_Alarm_Req(VOID)
{
    hal_rtc_t      CurrTime; // Current time
    hal_rtc_t      Alarm;    // Alarm time
    UINT32         SecondCurr        = 0;
    UINT32         SecondTmp         = 0;
    UINT32         SecondAlarmRecent = 0;
    UINT8          RecentAlarmId     = 0;
    UINT8          i;
    INT8           Ret;

    Hal_Rtc_Gettime(&CurrTime);
    printf("%s: %d/%d/%d, %d:%d\n", __FUNCTION__,
           CurrTime.tm_year, CurrTime.tm_mon, CurrTime.tm_mday, CurrTime.tm_hour, CurrTime.tm_min);
    SecondCurr = UI_Time_to_Seconds(&CurrTime);

    /*check the nearest time of alarm to the current time */
    for (i = 0; i < NV_ALARM_MAX_ALARM_NUM; i++)
    {
        if (TRUE == g_Alarm_Mng.Alarm.AlarmInfo[i].OnOff)
        {
            Alarm.tm_sec  = 0;
            Alarm.tm_min = g_Alarm_Mng.Alarm.AlarmInfo[i].Min
                + g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatCount * ALARM_RING_REPEAT_INTERVAL;
            Alarm.tm_hour = (g_Alarm_Mng.Alarm.AlarmInfo[i].Hour + Alarm.tm_min / 60) % 24;
            Alarm.tm_min  = Alarm.tm_min % 60;
            Alarm.tm_mday = CurrTime.tm_mday;
            Alarm.tm_mon  = CurrTime.tm_mon;
            Alarm.tm_year = CurrTime.tm_year;

            SecondTmp = UI_Time_to_Seconds(&Alarm);
            if ((0 == (g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatBitmap & 0x80)) // alarm once
                || (0 != (g_Alarm_Mng.Alarm.AlarmInfo[i].RepeatBitmap
                          & (0x01 << CurrTime.tm_wday)))) // alarm repeat
            {
                if (SecondTmp <= SecondCurr)
                {
                    if (SecondTmp > SecondAlarmRecent)
                    {
                        SecondAlarmRecent = SecondTmp;
                        RecentAlarmId     = 0x01 << i;
                    }
                    else if (SecondTmp == SecondAlarmRecent)
                    {
                        RecentAlarmId |= 0x01 << i;
                    }
                }
            }
        }
    }
    g_Alarm_Mng.RtcAlarmId = RecentAlarmId;

    /*check the nearest time of calendar alarm to the current time */
    Ret = Alarm_Calendar_Check_PowerOff_Alarm(&CurrTime, SecondAlarmRecent);
    printf("%s: Ret %d, RecentAlarmId %d\n", __FUNCTION__, Ret, g_Alarm_Mng.RtcAlarmId);
    if(0 < Ret) // calendar alarm not ringing
    {
        if (0 < RecentAlarmId)
        {
            Alarm_Ringing_Cb();
        }
        else
        {
            printf("%s: error AlarmId %d, not alarm is ringring!\n", __FUNCTION__, RecentAlarmId);
        }
    }
}

/**
 * Framework inform alarm module of power on completely
 * param (in) VOID
 * return  VOID
 */
VOID Framework_Alarm_PowerOn_Complete_Req(VOID)
{
    Alarm_Set_Recent_Alarm(TRUE, FALSE);
}

/**
 * calendar Check whether alarm is ringing in alarm module
 * param (in) VOID
 * return  BOOL
 */
BOOL Alarm_Calendar_Check_Alarm_Ringing(VOID)
{
    printf("%s: rtc alarm id %d\n", __FUNCTION__, g_Alarm_Mng.RtcAlarmId);
    if (0 < g_Alarm_Mng.RtcAlarmId)
    {
        Alarm_Ringing_Cb();
        return(TRUE);
    }
    return(FALSE);
}

/**
 * Calendar Informs alarm that the alarm information of reminder is changed
 * param (in) ZeroSec: BOOL, current time(min:sec) is XX:00 not XX:59 if TRUE
 * return  VOID
 */
VOID Alarm_Calendar_Alarm_Change_Ind(BOOL ZeroSec)
{
    printf("%s: RtcAlarmId %d, ZeroSec %d\n", __FUNCTION__, g_Alarm_Mng.RtcAlarmId, ZeroSec);
    Alarm_Set_Recent_Alarm(FALSE, ZeroSec);
}

/**
 * Inform alarm and calendar that the time is changed
 * param (in) VOID
 * return VOID
 */
VOID Setting_Time_Change_Ind(VOID)
{
    printf("%s\n", __FUNCTION__);
    Alarm_Calendar_Clear_Alarm_Req();
    Alarm_Set_Recent_Alarm(TRUE, FALSE);
}
